package org.yaac.server.egql.evaluator;

import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Sets.newHashSet;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.yaac.server.egql.EntityProperty;
import org.yaac.server.egql.exception.EGQLException;
import org.yaac.server.egql.processor.ProcessData.ProcessDataRecord;
import org.yaac.server.util.DatastoreUtil;

/**
 * @author Max Zhu (thebbsky@gmail.com)
 *
 */
public class InEvaluator extends Evaluator {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * target to compare with
	 */
	private final Evaluator target;
	
	private final List<Evaluator> ops;

	/**
	 * true = in
	 * false = not in
	 */
	private final boolean inFlag;

	public InEvaluator(Evaluator target, boolean inFlag) {
		super();
		this.target = target;
		this.inFlag = inFlag;
		this.ops = new LinkedList<Evaluator>();
	}

	public InEvaluator add(Evaluator op) {
		ops.add(op);
		return this;
	}

	/**
	 * append delta to parent evaluator text, because this text can't be constructed at once
	 * 
	 * @param delta
	 */
	public void appendText(String delta) {
		if (isNullOrEmpty(getText())) {
			setText(delta);
		} else {
			setText(getText() + delta);
		}
	}
	
	@Override
	public EvaluationResult evaluate(ProcessDataRecord record) {
		EvaluationResult r = target.evaluate(record);
		
		boolean result = false;
		for (Evaluator e : ops) {
			if (DatastoreUtil.deterministicCompare(r.getPayload(), e.evaluate(record).getPayload()) == 0) {
				result = true;
				break;
			}
		}
		
		// if we include all previous results into one, then it will be bit slow as it's not necessary to evaluate all of them
		return new EvaluationResult(result == inFlag, r).withTitle(this.getText());
	}
	
	@Override
	public Set<AggregationEvaluator> aggregationChildren() {
		Set<AggregationEvaluator> result = newHashSet(target.aggregationChildren());
		for (Evaluator op : ops) {
			result.addAll(op.aggregationChildren());
		}
		return result;
	}
	
	@Override
	public Set<EntityProperty> nonAggregationProperties() {
		Set<EntityProperty> result = newHashSet(target.nonAggregationProperties());
		for (Evaluator op : this.ops) {
			result.addAll(op.nonAggregationProperties());
		}
		return result;
	}
	
	@Override
	public void validate() throws EGQLException {
	}
}
